using NUnit.Framework;
using Tycho.Lexer;
using Tycho.Parser.Peg;
using Tycho.Parser.Tokens;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class MultipleRuleSpecification {
        [Test]
        public void ZeroOrMoreParseShouldSucceedWhenNothingParsed () {
            var m = new MultipleRule<object> (0, -1, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void OneOrMoreParseShouldSucceedWhenJustOneParsed () {
            var m = new MultipleRule<object> (1, -1, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("x").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ThreeOrMoreParseShouldFailWhenJustTwoParsed () {
            var m = new MultipleRule<object> (3, -1, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("x x").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNull (result);
        }

        [Test]
        public void OneToTwoParseShouldSucceedWhenThreeFoundToParse () {
            var m = new MultipleRule<object> (1, 2, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("x x x").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (2, result.Index);
        }

        [Test]
        public void OneToTwoParseShouldFailWhenNoneFoundToParse () {
            var m = new MultipleRule<object> (1, 2, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("y").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNull (result);
        }

        [Test]
        public void ZeroOrMoreParseShouldSucceedWhenNoneFoundToParse () {
            var m = new MultipleRule<object> (0, -1, new KeywordRule<object> ("x"));

            Token [] tokens = NativeLexer.Lex ("y").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void ParseShouldReturnAllCapturesWhenSuccessful () {
            var m = new MultipleRule<object> (0, -1, new NamedRule<object> ("id", new IdentifierTerminal<object> ()));

            Token [] tokens = NativeLexer.Lex ("a b c").ToArray ();

            var result = m.Parse (tokens, 0, null);

            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Captures.Count);
            result.AssertCaptureIs (0, "id", "a");
            result.AssertCaptureIs (1, "id", "b");
            result.AssertCaptureIs (2, "id", "c");
        }
    }

    static class CaptureHelper {
        public static void AssertCaptureIs<C> (this RuleParseResult<C> result, int index, string name, string identifier) {
            Assert.AreEqual (name, result.Captures [index].Name);
            Assert.AreEqual (identifier, ((IdentifierTerm) result.Captures [index].Term).Name);
        }
    }
}